//
// Created by benxb on 2021/12/1.
//
#include <gtest/gtest.h>
#include <cstdio>
#include <zlib.h>
#include <fstream>
#include "compress/compressor.h"
#include <compress/lz4.h>
#include <chrono>

using namespace benxdb;

const std::string data_file = "/home/ubuntu/benxdb/test/compress/lidar_data_0.txt";

TEST(ZlibTest, TestSimpleCompress)
{
    /* 原始数据 */
    unsigned char strSrc[] = "hello world! aaaaa bbbbb ccccc ddddd 中文测试 yes";
    unsigned char buf[1024] = {0};
    unsigned char strDst[1024] = {0};
    unsigned long srcLen = sizeof(strSrc);
    unsigned long bufLen = sizeof(buf);
    unsigned long dstLen = sizeof(strDst);

    printf("Src string:%s\nLength:%ld\n", strSrc, srcLen);

    /* 压缩 */
    compress(buf, &bufLen, strSrc, srcLen);
    printf("After Compressed Length:%ld\n", bufLen);

    /* 解压缩 */
    uncompress(strDst, &dstLen, buf, bufLen);
    printf("After UnCompressed Length:%ld\n",dstLen);

    printf("UnCompressed String:%s\n",strDst);
}


TEST(ZlibTest, TestFileCompressDecimal) {
    std::ifstream data_io(data_file, std::ios::binary | std::ios::in);
    if (!data_io) {
        return;
    }
    char line[1000];
    float x, y, z, intensity;
    std::vector<float> x_column;
    while (data_io.getline(line, 100)) {
        sscanf(line, "%f %f %f %f", &x, &y, &z, &intensity);
        x_column.push_back(x);
        if (x_column.size() > 64000) {
            break;
        }
    }
    auto *in_data = (unsigned char*)malloc(x_column.size()*sizeof(float));
    for (int i = 0; i < x_column.size(); i++) {
        memcpy(in_data+i*sizeof(float), &x_column[i], sizeof(float));
    }

    auto start = std::chrono::steady_clock::now();
    auto *out = (unsigned char*)malloc(x_column.size()*sizeof(float));
    unsigned long out_size = x_column.size() * sizeof(float);
    /* 压缩 */
    compress(out, &out_size, in_data, x_column.size() * sizeof(float));

    printf("Src string Length:%ld\n", x_column.size() * sizeof(float));
    printf("After Compressed Length:%ld\n", out_size);
    auto end = std::chrono::steady_clock::now();
    std::chrono::duration<double> time_span = std::chrono::duration_cast<std::chrono::duration<double>>(end - start);
    std::cout << "Compress End, spend " << time_span.count() << std::endl;
}


TEST(ZlibTest, TestCompressorAndZlib) {
    benxdb::Compressor compressor;
    std::ifstream data_io(data_file, std::ios::binary | std::ios::in);
    if (!data_io) {
        return;
    }
    char line[1000];
    float x, y, z, intensity;
    std::vector<float> x_column;
    int count = 0;
    while (data_io.getline(line, 100)) {
        sscanf(line, "%f %f %f %f", &x, &y, &z, &intensity);
        x_column.push_back(x);
        if (x_column.size() > 64000) {
            break;
        }
    }

    std::string in_data_str;
    in_data_str.resize(x_column.size()*sizeof(float));
    for (int i = 0; i < x_column.size(); i++) {
        memcpy((void *) (in_data_str.data() + i * sizeof(float)), &x_column[i], sizeof(float));
    }

    auto start = std::chrono::steady_clock::now();
    std::string out_str;
    compressor.DeltaEncodeFloatWithPadding(const_cast<char *>(in_data_str.data()), in_data_str.size(), 6, out_str);

    printf("After Compressed Length:%ld\n", out_str.size());

    auto *in_data = (unsigned char*)malloc(out_str.size() + 1);
    strcpy((char *)in_data, out_str.data());

    auto *out = (unsigned char*)malloc(out_str.size());
    unsigned long out_size = out_str.size();
    /* 压缩 */
    compress(out, &out_size, in_data, out_str.size());

    printf("Src string Length:%ld\n", x_column.size() * sizeof(float));
    printf("After Compressed Length:%ld\n", out_size);
    auto end = std::chrono::steady_clock::now();
    std::chrono::duration<double> time_span = std::chrono::duration_cast<std::chrono::duration<double>>(end - start);
    std::cout << "Compress End, spend " << time_span.count() << std::endl;
}

TEST(LZ4Test, TestFileCompressDecimal) {
    std::ifstream data_io(data_file, std::ios::in);
    if (!data_io) {
        return;
    }
    char line[1000];
    float x, y, z, intensity;
    std::vector<float> x_column;
    while (data_io.getline(line, 100)) {
        sscanf(line, "%f %f %f %f", &x, &y, &z, &intensity);
        x_column.push_back(x);
        if (x_column.size() > 64000) {
            break;
        }
    }
    int in_size = x_column.size() * sizeof(float);
    char *in_data = (char*)malloc(in_size);
    for (int i = 0; i < x_column.size(); i++) {
        memcpy(in_data+i*sizeof(float), &x_column[i], sizeof(float));
    }

    auto start = std::chrono::steady_clock::now();
    const int max_dst_size = LZ4_compressBound(in_size);
    char *out = (char*)malloc(max_dst_size);
    /* 压缩 */
    int out_size = LZ4_compress_default(in_data, out, in_size, max_dst_size);
//    int out_size = LZ4_compress_fast(in_data, out, in_size, max_dst_size, 1);

    printf("max_dst_size :%ld\n", max_dst_size);
    printf("Src string Length:%ld\n", in_size);
    printf("After Compressed Length:%ld\n", out_size);
    auto end = std::chrono::steady_clock::now();
    std::chrono::duration<double> time_span = std::chrono::duration_cast<std::chrono::duration<double>>(end - start);
    std::cout << "Compress End, spend " << time_span.count() << std::endl;
}

TEST(LZ4Test, TestCompressorAndLZ4) {
    benxdb::Compressor compressor;
    std::ifstream data_io(data_file, std::ios::binary | std::ios::in);
    if (!data_io) {
        return;
    }
    char line[1000];
    float x, y, z, intensity;
    std::vector<double> x_column;
    int count = 0;
    while (data_io.getline(line, 100)) {
        sscanf(line, "%f %f %f %f", &x, &y, &z, &intensity);
        x_column.push_back(x);
        if (x_column.size() > 64000) {
            break;
        }
    }

    std::string in_data_str;
    in_data_str.resize(x_column.size()*sizeof(double));
    for (int i = 0; i < x_column.size(); i++) {
        memcpy((void *) (in_data_str.data() + i * sizeof(double)), &x_column[i], sizeof(double));
    }

    auto start = std::chrono::steady_clock::now();
    std::string out_str;
    compressor.DeltaEncodeDecimal(const_cast<char *>(in_data_str.data()), in_data_str.size(), 6, out_str);

    printf("After Compressed Length:%ld\n", out_str.size());

    char *in_data = (char*)malloc(out_str.size());
    memcpy(in_data, out_str.data(), out_str.size());
    int in_size = out_str.size();

    const int max_dst_size = LZ4_compressBound(in_size);
    char *out = (char*)malloc(max_dst_size);
    /* 压缩 */
    int out_size = LZ4_compress_default(in_data, out, in_size, max_dst_size);

    printf("Src string Length:%ld\n", x_column.size() * sizeof(float));
    printf("After Compressed Length:%d\n", out_size);
    auto end = std::chrono::steady_clock::now();
    std::chrono::duration<double> time_span = std::chrono::duration_cast<std::chrono::duration<double>>(end - start);
    std::cout << "Compress End, spend " << time_span.count() << std::endl;
}